package models;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import tp.badugi.server.Action;
import tp.badugi.server.Card;
import tp.badugi.server.Player;
import tp.badugi.server.Table;

@Aspect
public class LogAspect {
	
	private PrintWriter writer;
	
	// Before game starts create file
	@Before("execution(* tp.badugi.server.Table.addPlayer(..))")
    public synchronized void logAddPlayer(JoinPoint jp){
		
		if (writer == null) {
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
			Date date = new Date();
			
			String fileName = dateFormat.format(date) + ".txt";
	        
			try {
				this.writer = new PrintWriter("logs/"+fileName, "UTF-8");
				
			} catch (FileNotFoundException | UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		
		Object[] args = jp.getArgs();
		String playerName = (String) args[0];
		writer.println(playerName + " joined the game.");
		writer.flush();
    }
	
	@Before("execution(* announceRoundChange(..))")
	public void logAnnounceRoundChange(JoinPoint jp) {
		Object[] args = jp.getArgs();
		int bettingRound = (int) args[0];
		if (bettingRound == 1) {
			Table table = (Table) jp.getThis();
			List<Player> players = table.getPlayerList();
			for (Player player : players) {
				writer.print(player.getName() + " received cards:");
				for (Card card : player.getCards()) {
					writer.print(" " + card.toString());
				}
				writer.println(".");
			}
			writer.flush();
		}
	}
	
	@Before("execution(* announcePlayersAction(..))")
	public void logAnnouncePlayersAction(JoinPoint jp) {
		Object[] args = jp.getArgs();
		Player playerInAction = (Player) args[0];
		Action action = (Action) args[1];
		String actionStr = "";
		switch (action) {
		case FOLD:
			actionStr = "folded";
			break;
		case CHECK:
			actionStr = "checked";
			break;
		case CALL:
			actionStr = "called";
			break;
		case BET:
			actionStr = "bet " + action.amount;
			break;
		case RAISE:
			actionStr = "raised by " + action.amount;
			break;
		case ALL_IN:
			actionStr = "went all-in";
			break;
		}
		writer.println(playerInAction.getName() + " " + actionStr + ".");
		writer.flush();
	}
	
	@Before("execution(* announcePlayerReplacedCards(..))")
	public void logAnnouncePlayerReplacedCards(JoinPoint jp) {
		Object[] args = jp.getArgs();
		Player playerWithCards = (Player) args[0];
		int cardCount = (int) args[1];
		writer.print(playerWithCards.getName() + " replaced " + cardCount + " cards. Player's hand:");
		for (Card card : playerWithCards.getCards()) {
			writer.print(" " + card.toString());
		}
		writer.println(".");
		writer.flush();
	}
	
	@Before("execution(* announceWinnersRevealed(..))")
	public void logAnnounceWinnersRevealed(JoinPoint jp) {
		Object[] args = jp.getArgs();
		List<Player> winners = (List<Player>) args[0];
		for (Player winner : winners) {
			writer.println(winner.getName() + " won!");
			writer.println();
		}
		
		Table table = (Table) jp.getThis();
		List<Player> players = table.getPlayerList();
		for (Player player : players) {
			writer.println(player.getName() + " now has " + player.getChipCount() + " chips.");
		}
		writer.flush();
	}

}
